
// const pointLightCount: i32 = 16;

@group(0) @binding(0) var positionTexture: texture_2d<f32>;
@group(0) @binding(1) var normalTexture: texture_2d<f32>;
@group(0) @binding(2) var colorTexture: texture_2d<f32>;
@group(0) @binding(3) var<uniform> lightProjection : mat4x4<f32>;
@group(0) @binding(4) var shadowMap: texture_depth_2d;
@group(0) @binding(5) var shadowSampler: sampler_comparison;

// 使用 u32 表示布尔值
struct ShadowSettings {
    enabled: u32, 
};

@group(0) @binding(6) var<uniform> shadowSettings: ShadowSettings;

@group(1) @binding(0) var<uniform> ambientIntensity : f32;
@group(1) @binding(1) var<uniform> pointLightOption : vec4<f32>;
@group(1) @binding(2) var<uniform> pointLightPosition : array<vec4<f32>, pointLightCount>;
@group(1) @binding(3) var<uniform> directionLight : array<vec4<f32>, 2>;
@group(1) @binding(4) var<uniform> modelViewAll : mat4x4<f32>;
@group(1) @binding(5) var<uniform> pointColors : array<vec3<f32>, pointLightCount>;

@fragment
fn main(@builtin(position) fragCoord: vec4<f32>) -> @location(0) vec4<f32> {
            // 从 G-Buffer 中读取数据
    let fragPositionv4 = textureLoad(positionTexture, vec2<i32>(fragCoord.xy), 0);
    let fragPosition = (modelViewAll * fragPositionv4).xyz;
    let oNormal = textureLoad(normalTexture, vec2<i32>(fragCoord.xy), 0);
    let fragNormal = normalize(oNormal.xyz);
    let albedo = textureLoad(colorTexture, vec2<i32>(fragCoord.xy), 0);


    // directional Light Shadow
    let posFromLight: vec4<f32> = lightProjection * fragPositionv4;
    // Convert shadowPos XY to (0, 1) to fit texture UV
    var shadowPos: vec3<f32> = vec3<f32>(posFromLight.xy * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5, 0.5), posFromLight.z);

    var shadow: f32 = 0.0;
    
    if (shadowSettings.enabled == 1) {
    // apply Percentage-closer filtering (PCF)
    // sample nearest 9 texels to smooth result
        let size = f32(textureDimensions(shadowMap).x);
        for (var y: i32 = -1 ; y <= 1 ; y = y + 1) {
            for (var x: i32 = -1 ; x <= 1 ; x = x + 1) {
                let offset = vec2<f32>(f32(x) / size, f32(y) / size);
                shadow = shadow + textureSampleCompare(
                    shadowMap,
                    shadowSampler,
                    shadowPos.xy + offset,
                    shadowPos.z - 0.005  // apply a small bias to avoid acne
                );
            }
        }
        shadow = shadow / 9.0;
    } else {
        shadow = 1.0;
    }

    let useNormal = oNormal.w > 0.5;
    if !useNormal {
        return albedo;
    }

    let objectColor = albedo.rgb;
    let ambintLightColor = vec3(1.0, 1.0, 1.0);
    let pointLightColor = vec3(1.0, 1.0, 1.0);
    let dirLightColor = vec3(1.0, 1.0, 1.0);

    var lightResult = vec3(0.0, 0.0, 0.0);
    // ambient
    lightResult += ambintLightColor * ambientIntensity;
    // Directional Light
    var directionPosition = directionLight[0].xyz;
    var directionIntensity: f32 = directionLight[1][0];

    directionPosition = (modelViewAll * vec4<f32>(directionPosition, 0.0)).xyz;

    var diffuse: f32 = max(dot(normalize(directionPosition), fragNormal), 0.0);

    var directionLight: vec3<f32> = dirLightColor * directionIntensity * diffuse;


    lightResult += directionLight * shadow;

    // Point Light

    var pointIntensity: f32 = pointLightOption[0];
    var pointRadius: f32 = pointLightOption[1];

    for (var i = 0; i < pointLightCount; i++) {
        var pointPosition = (modelViewAll * vec4<f32>(pointLightPosition[i].xyz, 1.0)).xyz;
        // var pointPosition = pointLightPosition[i].xyz;
        var L = pointPosition - fragPosition;
        var distance = length(L);
        if distance < pointRadius {
            var diffuse: f32 = max(dot(normalize(L), fragNormal), 0.0);
            var distanceFactor: f32 = pow(1.0 - distance / pointRadius, 2.0);
            lightResult += pointColors[i] * pointIntensity * diffuse * distanceFactor;
        }
    }

    return vec4<f32>(objectColor * lightResult, 1.0);

    //// 简单光照计算（示例）
    // let lightDir = normalize(vec3<f32>(1.0, 1.0, 1.0));
    // let diffuse = max(dot(normal.xyz, lightDir), 0.0);
    // let color = albedo.rgb * diffuse;

    // return vec4<f32>(color, 1.0);
}